package com.jichangxiu.framework.utils;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.jichangxiu.common.annotation.Log;
import com.jichangxiu.common.context.JcxContext;
import com.jichangxiu.common.entity.rule.LogRule;
import com.jichangxiu.common.entity.vo.Result;
import com.jichangxiu.common.enums.LogType;
import com.jichangxiu.common.utils.IpUtils;
import com.jichangxiu.common.utils.ServletUtils;
import com.jichangxiu.framework.factory.LogRuleAsyncFactory;
import com.jichangxiu.framework.factory.LogRuleServiceFactory;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.http.HttpMethod;

import javax.servlet.http.HttpServletRequest;

@Slf4j
public class LogRuleUtils {

    public static Object recordRequestLog(ProceedingJoinPoint proceedingJoinPoint, Log logAnnotation, Long startTime) throws Throwable {
        LogRule logRule = getLog(proceedingJoinPoint, logAnnotation);
        Object object;
        try {
            object = proceedingJoinPoint.proceed();
            log.info("【LogUtils】业务耗时：" + (System.currentTimeMillis() - startTime));
            logRule.setResult(JSONUtil.toJsonStr(Result.toResult(object)));
        } catch (Exception ex) {
            log.error("【LogUtils】请求地址【" + ServletUtils.getRequestUri() + "】记录请求日志异常", ex);
            logRule.setStatus(false);
            logRule.setException(JSONUtil.toJsonStr(ex));
            throw ex;
        } finally {
            // 保存数据库
            logRule.setDuration(System.currentTimeMillis() - startTime);
            log.info("【LogUtils】请求耗时：" + (System.currentTimeMillis() - startTime));
            AsyncUtils.getINSTANCE().execute(LogRuleAsyncFactory.recordLogRule(LogRuleServiceFactory.logRuleService(), logRule));
        }
        return object;
    }

    private static LogRule getLog(ProceedingJoinPoint proceedingJoinPoint, com.jichangxiu.common.annotation.Log logAnnotation) {
        LogRule logRule = new LogRule();
        logRule.setStatus(true);
        logRule.setException(JSONUtil.toJsonStr("{}"));
        logRule.setRemark(logAnnotation.remark());
        if (ObjectUtil.isNotNull(proceedingJoinPoint)) {
            logRule.setModule(AopUtils.getClassName(proceedingJoinPoint));
            logRule.setHandle(AopUtils.getMethodName(proceedingJoinPoint));
            logRule.setParam(JSONUtil.toJsonStr(AopUtils.getParameterArguments(proceedingJoinPoint)));
        }
        HttpServletRequest httpServletRequest = ServletUtils.getRequest();
        if (ObjectUtil.isNotNull(httpServletRequest)) {
            logRule.setAction(httpServletRequest.getRequestURI());
            logRule.setAddress(IpUtils.getClientIp(httpServletRequest));
            logRule.setBrowser(IpUtils.getClientBrowser(httpServletRequest));
            logRule.setSystem(IpUtils.getClientOs(httpServletRequest));
            String method = httpServletRequest.getMethod();
            logRule.setMethod(method);
            if (HttpMethod.POST.matches(method))
                logRule.setType(LogType.ADD.name());
            else if (HttpMethod.DELETE.matches(method))
                logRule.setType(LogType.DEL.name());
            else if (HttpMethod.PUT.matches(method))
                logRule.setType(LogType.EDIT.name());
            else if (HttpMethod.GET.matches(method))
                logRule.setType(LogType.QUERY.name());
            else
                logRule.setType(LogType.OTHER.name());
        }
        String tenantId = JcxContext.getTenantId();
        if (StrUtil.isNotBlank(tenantId))
            logRule.setTenantId(tenantId);
        String userId = JcxContext.getUserId();
        if (StrUtil.isNotBlank(userId)) {
            logRule.setUserId(userId);
            logRule.setCreateBy(userId);
            logRule.setUpdateBy(userId);
        }
        String deptId = JcxContext.getDeptId();
        if (StrUtil.isNotBlank(deptId))
            logRule.setDeptBy(deptId);
        return logRule;
    }

    public static void fillLocation(LogRule logRule) {
        if (ObjectUtil.isNotEmpty(logRule) && StrUtil.isNotEmpty(logRule.getAddress())) {
            logRule.setLocation(IpUtils.getRealAddress(logRule.getAddress()));
        }
    }

}
